package com.randb.easyhttp;

import android.app.Application;
import android.content.Context;
import android.text.TextUtils;

import com.randb.easyhttp.cache.RxCache;
import com.randb.easyhttp.cache.coverter.IDiskConverter;
import com.randb.easyhttp.cache.model.CacheMode;
import com.randb.easyhttp.cookie.CookieManager;
import com.randb.easyhttp.https.HttpsUtils;
import com.randb.easyhttp.interceptor.HttpLoggingInterceptor;
import com.randb.easyhttp.model.HttpHeaders;
import com.randb.easyhttp.model.HttpParams;
import com.randb.easyhttp.request.CustomRequest;
import com.randb.easyhttp.request.DeleteRequest;
import com.randb.easyhttp.request.DownloadRequest;
import com.randb.easyhttp.request.GetRequest;
import com.randb.easyhttp.request.PostRequest;
import com.randb.easyhttp.request.PutRequest;
import com.randb.easyhttp.utils.HttpLog;
import com.randb.easyhttp.utils.RxUtils;
import com.randb.easyhttp.utils.Utils;

import java.io.File;
import java.io.InputStream;
import java.net.Proxy;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;

/**
 * User: RandBII
 * Date: 2020/5/8
 * Description:
 */

@SuppressWarnings(value = {"uncheck", "CheckResult"})
public class EasyHttp {

    private static Application sContext;
    public static final int DEFAULT_MILLISECONDS = 60000;             //默认的超时时间
    private static final int DEFAULT_RETRY_COUNT = 3;                 //默认重试次数
    private static final int DEFAULT_RETRY_INCREASEDELAY = 0;         //默认重试叠加时间
    private static final int DEFAULT_RETRY_DELAY = 500;               //默认重试延时
    public static final int DEFAULT_CACHE_NEVER_EXPIRE = -1;          //缓存过期时间，默认永久缓存
    private Cache mCache = null;                                      //Okhttp缓存对象
    private CacheMode mCacheMode = CacheMode.NO_CACHE;                //缓存类型
    private long mCacheTime = -1;                                     //缓存时间
    private File mCacheDirectory;                                     //缓存目录
    private long mCacheMaxSize;                                       //缓存大小
    private String mBaseUrl;                                          //全局BaseUrl
    private int mRetryCount = DEFAULT_RETRY_COUNT;                    //重试次数默认3次
    private int mRetryDelay = DEFAULT_RETRY_DELAY;                    //延迟xxms重试
    private int mRetryIncreaseDelay = DEFAULT_RETRY_INCREASEDELAY;    //叠加延迟
    private HttpHeaders mCommonHeaders;                               //全局公共请求头
    private HttpParams mCommonParams;                                 //全局公共请求参数
    private OkHttpClient.Builder okHttpClientBuilder;                 //okhttp请求的客户端
    private Retrofit.Builder retrofitBuilder;                         //Retrofit请求Builder
    private RxCache.Builder rxCacheBuilder;                           //RxCache请求的Builder
    private CookieManager cookieJar;                                   //Cookie管理
    private volatile static EasyHttp singleton = null;


    public static EasyHttp getInstance() {
        testInitialize();
        if (singleton == null) {
            synchronized (EasyHttp.class) {
                if (singleton == null) {
                    singleton = new EasyHttp();
                }
            }
        }
        return singleton;
    }

    /**
     * 必须在全局Application先调用，获取context上下文，否则缓存无法使用
     */
    public static void init(Application app) {
        sContext = app;
    }

    /**
     * 获取全局上下文
     */
    public static Context getContext() {
        testInitialize();
        return sContext;
    }

    /**
     * 获取全局baseurl
     */
    public static String getBaseUrl() {
        return getInstance().mBaseUrl;
    }

    private static void testInitialize() {
        if (sContext == null)
            throw new ExceptionInInitializerError("请先在全局Application中调用 EasyHttp.init() 初始化！");
    }

    public static OkHttpClient getOkHttpClient() {
        return getInstance().okHttpClientBuilder.build();
    }

    public static Retrofit getRetrofit() {
        return getInstance().retrofitBuilder.build();
    }

    public static RxCache getRxCache() {
        return getInstance().rxCacheBuilder.build();
    }

    public static OkHttpClient.Builder getOkHttpClientBuilder() {
        return getInstance().okHttpClientBuilder;
    }

    public static Retrofit.Builder getRetrofitBuilder() {
        return getInstance().retrofitBuilder;
    }

    public static RxCache.Builder getRxCacheBuilder() {
        return getInstance().rxCacheBuilder;
    }

    public static CookieManager getCookieJar() {
        return getInstance().cookieJar;
    }

    public static File getCacheDirectory() {
        return getInstance().mCacheDirectory;
    }

    public static long getCacheMaxSize() {
        return getInstance().mCacheMaxSize;
    }

    public EasyHttp debug(String tag) {
        debug(tag, true);
        return this;
    }

    private EasyHttp debug(String tag, boolean b) {
        String tempTag = TextUtils.isEmpty(tag) ? "RxEasyHttp_" : tag;
        if (b) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(tempTag, b);
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            okHttpClientBuilder.addInterceptor(loggingInterceptor);
        }
        HttpLog.customTagPrefix = tempTag;
        HttpLog.allowE = b;
        HttpLog.allowD = b;
        HttpLog.allowI = b;
        HttpLog.allowV = b;
        return this;
    }

    public static CacheMode getCacheMode() {
        return getInstance().mCacheMode;
    }

    public static long getCacheTime() {
        return getInstance().mCacheTime;
    }

    public static int getRetryCount() {
        return getInstance().mRetryCount;
    }

    public static int getRetryDelay() {
        return getInstance().mRetryDelay;
    }


    public int getRetryIncreaseDelay() {
        return getInstance().mRetryIncreaseDelay;
    }


    public Cache getHttpCache() {
        return getInstance().mCache;
    }

    public HttpParams getCommonParams() {
        return getInstance().mCommonParams;
    }

    public HttpHeaders getCommonHeaders() {
        return getInstance().mCommonHeaders;
    }


    public class DefaultHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    public EasyHttp setHostnameVerifier(HostnameVerifier verifier) {
        okHttpClientBuilder.hostnameVerifier(verifier);
        return this;
    }

    public EasyHttp setCertificates(InputStream... certificates) {
        HttpsUtils.SSLParams sslParams = HttpsUtils.getSSLSocketFactory(null,
                null, certificates);
        okHttpClientBuilder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager);
        return this;
    }

    public EasyHttp setCertificates(InputStream bksFile, String password, InputStream... certificates) {
        HttpsUtils.SSLParams params = HttpsUtils.getSSLSocketFactory(bksFile, password, certificates);
        okHttpClientBuilder.sslSocketFactory(params.sSLSocketFactory, params.trustManager);
        return this;
    }

    public EasyHttp setCookieStore(CookieManager cookieManager) {
        cookieJar = cookieManager;
        okHttpClientBuilder.cookieJar(cookieJar);
        return this;
    }


    public EasyHttp setReadTimeOut(long readTimeOut) {
        okHttpClientBuilder.readTimeout(readTimeOut, TimeUnit.MILLISECONDS);
        return this;
    }

    public EasyHttp setWriteTimeOut(long writeTimeOut) {
        okHttpClientBuilder.writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS);
        return this;
    }

    public EasyHttp setConnectTimeOut(long connectTimeout) {
        okHttpClientBuilder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS);
        return this;
    }

    public EasyHttp setRetryCount(int count) {
        if (count < 0) throw new IllegalArgumentException("retry count must > 0 ");
        mRetryCount = count;
        return this;
    }


    public EasyHttp setRetryDelay(int retryDelay) {
        if (retryDelay < 0) throw new IllegalArgumentException("retryDelay must > 0");
        mRetryDelay = retryDelay;
        return this;
    }

    public EasyHttp setRetryIncreaseDelay(int retryIncreaseDelay) {
        if (retryIncreaseDelay < 0) {
            throw new IllegalArgumentException("retryIncreaseDelay must > 0");
        }
        mRetryIncreaseDelay = retryIncreaseDelay;
        return this;

    }


    public static int getRetryIncreasedelay() {
        return getInstance().mRetryIncreaseDelay;
    }


    public EasyHttp setCacheMode(CacheMode cacheMode) {
        cacheMode = cacheMode;
        return this;
    }


    public EasyHttp setCacheTime(long cacheTime) {
        if (cacheTime <= -1) {
            cacheTime = DEFAULT_CACHE_NEVER_EXPIRE;
        }
        mCacheTime = cacheTime;
        return this;
    }

    public EasyHttp setCacheMaxSize(long maxSize) {
        mCacheMaxSize = maxSize;
        return this;
    }

    public EasyHttp setCacheDirectory(File directory) {
        mCacheDirectory = Utils.checkNotNull(directory, "directory == null");
        rxCacheBuilder.diskDir(directory);
        return this;
    }

    public EasyHttp setCacheDiskConverter(IDiskConverter converter) {
        rxCacheBuilder.diskConverter(Utils.checkNotNull(converter, "converter == null "));
        return this;
    }

    public EasyHttp setHttpCache(Cache cache) {
        this.mCache = cache;
        return this;
    }

    public EasyHttp addCommonParams(HttpParams httpParams) {
        if (httpParams == null) httpParams = new HttpParams();
        httpParams.put(mCommonParams);
        return this;
    }

    public EasyHttp addInterceptor(Interceptor interceptor) {
        okHttpClientBuilder.addInterceptor(Utils.checkNotNull(interceptor, "interceptor == null "));
        return this;
    }

    public EasyHttp addNetworkInterceptor(Interceptor interceptor) {
        okHttpClientBuilder.addNetworkInterceptor(interceptor);
        return this;
    }

    public EasyHttp setOkProxy(Proxy proxy) {
        okHttpClientBuilder.proxy(Utils.checkNotNull(proxy, "proxy == null"));
        return this;
    }

    public EasyHttp setOkClient(OkHttpClient client) {
        retrofitBuilder.client(Utils.checkNotNull(client, "client == null"));
        return this;
    }

    public EasyHttp addConverterFactory(Converter.Factory factory) {
        retrofitBuilder.addConverterFactory(Utils.checkNotNull(factory, "factory == null"));
        return this;
    }

    public EasyHttp addCallAdapterFactory(CallAdapter.Factory factory) {
        retrofitBuilder.addCallAdapterFactory(Utils.checkNotNull(factory, "factory == null"));
        return this;
    }

    public EasyHttp setCallbackExecutor(Executor executor) {
        retrofitBuilder.callbackExecutor(Utils.checkNotNull(executor, "executor == null"));
        return this;
    }

    public EasyHttp setCallFactory(Call.Factory factory) {
        retrofitBuilder.callFactory(factory);
        return this;
    }

    public EasyHttp setBaseUrl(String baseUrl) {
        mBaseUrl = Utils.checkNotNull(baseUrl, "baseUrl == null");
        return this;
    }

    public static GetRequest get(String url) {
        return new GetRequest(url);
    }

    public static PostRequest post(String url) {
        return new PostRequest(url);
    }

    public static DeleteRequest delete(String url) {
        return new DeleteRequest(url);
    }

    public static CustomRequest custom() {
        return new CustomRequest();
    }

    public static DownloadRequest downLoad(String url) {
        return new DownloadRequest(url);
    }

    public static PutRequest put(String url) {
        return new PutRequest(url);
    }

    public static void cancelSubscription(Disposable disposable) {
        if (disposable != null && disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    @SuppressWarnings("CheckResult")
    public static void clearCache() {
        getRxCache().clear().compose(RxUtils.io_main())
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        HttpLog.i("clearCache success!!!");
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        HttpLog.i("clearCache err!!!");
                    }
                });
    }


    public static void removeCache(String key) {
        getRxCache().remove(key).compose(RxUtils.<Boolean>io_main()).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Exception {
                HttpLog.i("removeCache success!!!");
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                HttpLog.i("removeCache err!!!");
            }
        });
    }


}
